package codeg;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

import serialization.CodegSerializer;
import serialization.XMLCodegSerializer;

@XmlRootElement
public abstract class Codeg {
	private String id = "";
	private String version = "";
	private List<CodegChangeListener> listeners = new LinkedList<CodegChangeListener>();
	
	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String getVersion() {
		return version;
	}
	
	/**
	 * Adds a new listener for codeg changes if it is not already installed.
	 * @param listener a CodegChangeListener object.
	 */
	public void addListener(CodegChangeListener listener) {
	    if (listeners.contains(listener))
	        return;
	    if (listener != null)
	        listeners.add(listener);
	}
	
	/**
	 * Removes a codeg change listener if it is installed.
	 * @param listener the CodegChangeListener object to remove.
	 */
	public void removeListener(CodegChangeListener listener) {
	    listeners.remove(listener);
    }
   
    /**
     * Notifies listeners of a change in the codeg.
     */
	public void changed() {
	    Iterator<CodegChangeListener> i = listeners.iterator();
        while (i.hasNext()) {
            i.next().action();
        }
    }
	
   /**
    * Generates code based on a given code context.
    * @param context a CodegGenerationContext object.
    * @return a CodeGeneration object containing the code.
    * @throws CodegException whenever an error occurs when generating code or
    * checking preconditions.
    */
   abstract public CodeGeneration getCode(CodeGenerationContext context) throws CodegException;
    
    /**
     * Used by other codegs to discover the roles performed by this codeg.
     * A role is a string identifier that both codegs recognize, and use it when
     * asking for information and making decisions based on the roles.
     * @return an array of roles.
     */
    public String[] getRoles() { return null; }
    
    /**
     * Checkes whether a codeg implements a given role.
     * A role is a string identifier that both codegs recognize, and use it when
     * asking for information and making decisions based on the roles.
     * @param the role to look for.
     * @return true if the codeg implements the given role, false otherwise.
     */
    public boolean hasRole(String role) {
        String[] roles = getRoles();
        if (roles == null)
            return false;
        Arrays.sort(roles);
        return Arrays.binarySearch(roles, role) >= 0;
    }
    
    /**
     * Returns an information on request.
     * An information is an object used for communication, usually among codegs.
     * In a typical use case, an codeg checks if another implements a role, and
     * then asks for information based on this role.
     * @param id the information identifier
     * @return the object information or null if it is not available.
     */
    public Object getInformation(String id) {
        return null;
    }
    
    /**
     * Get a serializer for the codeg. The default is an XMLCodegSerializer object.
     * @return An XMLCodegSerializer object by default.
     */
    public static CodegSerializer getSerializer() {
        // The default codeg is assumed to be serialized to XML. 
        return new XMLCodegSerializer();
    }
}